package com.nova.bluetooth.xunFeiSDK.optionalFunction;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.iflytek.aiui.AIUIAgent;
import com.iflytek.aiui.AIUIConstant;
import com.iflytek.aiui.AIUIListener;
import com.nova.bluetooth.R;
import com.nova.bluetooth.xunFeiSDK.engine.AiuiEngine;
import com.nova.bluetooth.xunFeiSDK.engine.EngineConstants;
import com.nova.bluetooth.xunFeiSDK.recorder.AudioRecorder;
import com.nova.bluetooth.xunFeiSDK.recorder.RecorderFactory;
import com.nova.bluetooth.xunFeiSDK.recorder.SystemRecorder;
import com.nova.bluetooth.xunFeiSDK.utils.CopyAssetsUtils;
import com.nova.bluetooth.xunFeiSDK.utils.ErrorCode;
import com.nova.bluetooth.xunFeiSDK.utils.FileUtil;


import java.nio.charset.StandardCharsets;

/**
 * 动态实体demo
 * 注意事项：1.云端需要开通 “电话”技能
 * 2.参考文档：https://aiui.xfyun.cn/doc/aiui/3_access_service/access_interact/functions/user_individuality.html
 */
public class DynamicEntityActivity extends AppCompatActivity implements View.OnClickListener, View.OnLongClickListener {
    private static final String TAG = DynamicEntityActivity.class.getSimpleName();
    Handler handler = new Handler();
    private TextView mResText;
    private ScrollView mScrollView;
    private Button checkSysc;
    private Button sendDynamicText;
    private Button asrResult;
    // AIUI
    private AIUIAgent mAIUIAgent = null;

    /**
     * AIUI工作状态
     */
    private AudioRecorder recorder;

    /**
     * 记录上传动态实体的sid，查询是否创建成功
     */
    private String mSyncSid = "";

    /**
     * AIUI 回调信息处理
     */
    private AIUIListener mAIUIListener = event -> {
        switch (event.eventType) {
            case AIUIConstant.EVENT_CONNECTED_TO_SERVER:
                Log.i(TAG, "已连接服务器");
                break;

            case AIUIConstant.EVENT_CMD_RETURN: {
                if (AIUIConstant.CMD_SYNC == event.arg1) {    // 数据同步的返回
                    int dtype = event.data.getInt("sync_dtype", -1);
                    int retCode = event.arg2;

                    switch (dtype) {
                        case AIUIConstant.SYNC_DATA_SCHEMA: {
                            if (AIUIConstant.SUCCESS == retCode) {
                                // 上传成功，记录上传会话的sid，以用于查询数据打包状态
                                // 注：上传成功并不表示数据打包成功，打包成功与否应以同步状态查询结果为准，数据只有打包成功后才能正常使用
                                mSyncSid = event.data.getString("sid");
                                // 获取上传调用时设置的自定义tag
                                String tag = event.data.getString("tag");
                                setText("上传成功，sid=" + mSyncSid + "，tag=" + tag + "，你可以试着说“打电话给刘德华”");
                            } else {
                                mSyncSid = "";
                                setText("上传失败，错误码：" + retCode);
                            }
                        }
                        break;
                    }
                } else if (AIUIConstant.CMD_QUERY_SYNC_STATUS == event.arg1) {    // 数据同步状态查询的返回
                    // 获取同步类型
                    int syncType = event.data.getInt("sync_dtype", -1);
                    if (AIUIConstant.SYNC_DATA_QUERY == syncType) {
                        // 若是同步数据查询，则获取查询结果，结果中error字段为0则表示上传数据打包成功，否则为错误码
                        String result = event.data.getString("result");
                        setText(result);
                    }
                }
            }
            break;


            case AIUIConstant.EVENT_RESULT:
                if (event.info.contains("\"sub\":\"nlp")) {
                    JSONObject cntJson = JSON.parseObject(new String(event.data.getByteArray("0"), StandardCharsets.UTF_8));
                    JSONObject result = cntJson.getJSONObject("intent");
                    Log.i(TAG, "nlp result :" + result.toString());
                    //在线语义结
                    setText(result.toString());
                }
                break;

            case AIUIConstant.EVENT_ERROR:
                setText("错误码: " + event.arg1);
                setText("错误信息:" + event.info);
                setText("解决方案:" + ErrorCode.getError(event.arg1) + "\n  错误解决详情参考：https://www.yuque.com/iflyaiui/zzoolv/igbuol");
                break;
            case AIUIConstant.EVENT_STATE:    // 状态事件
                EngineConstants.mAIUIState = event.arg1;
                break;
            default:
                break;
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_asr);
        initLayout();
        // 资源拷贝
        CopyAssetsUtils.portingFile(this);
    }

    private void initLayout() {
        findViewById(R.id.init_sdk).setOnClickListener(this);
        findViewById(R.id.btnStartRecord).setOnClickListener(this);
        findViewById(R.id.btnStopRecord).setOnClickListener(this);
        findViewById(R.id.btnSave).setOnClickListener(this);
        findViewById(R.id.writeTest).setOnClickListener(this);
        TextView titleTextView = findViewById(R.id.myTitle);
        titleTextView.setText("动态实体demo");
        mScrollView = findViewById(R.id.scrollView);
        mResText = findViewById(R.id.res_text);
        mResText.setOnLongClickListener(this);
        Button btnStartRecord = findViewById(R.id.btnStartRecord);
        sendDynamicText = findViewById(R.id.btnStopRecord);
        sendDynamicText.setText("上传联系人");
        checkSysc = findViewById(R.id.btnSave);
        checkSysc.setText("查询上传结果");
        asrResult = findViewById(R.id.writeTest);
        asrResult.setText("");
        asrResult.setVisibility(View.VISIBLE);
        mResText.append("默认持续交互模式，在aiui.cfg修改continuous为oneshot为单轮交互 \n");
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
        if (id == R.id.init_sdk) {
            initSDK();
        } else if (id == R.id.btnStartRecord) {
            startRecord();
            //上传动态实体数据
        } else if (id == R.id.btnStopRecord) {
            syncContacts();
            //查询动态实体是否创建成功
        } else if (id == R.id.btnSave) {
            AiuiEngine.DynamicEntity_syncQuery(mSyncSid);
        }
    }

    @Override
    public boolean onLongClick(View view) {
        if (view.getId() == R.id.res_text) {
            ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
            ClipData clipData = ClipData.newPlainText(null, mResText.getText());
            clipboard.setPrimaryClip(clipData);
            Toast.makeText(this, "已复制到剪贴板", Toast.LENGTH_LONG).show();
        }
        return true;
    }

    private void initSDK() {
        //状态初始化
        EngineConstants.isRecording = false;
        //TODO 开发者需要实现生成sn的代码，参考：https://www.yuque.com/iflyaiui/zzoolv/tgftb5
        //注意事项1: sn每台设备需要唯一！！！！WakeupEngine的sn和AIUI的sn要一致
        //注意事项2: 获取的值要保持稳定，否则会重复授权，浪费授权量
        EngineConstants.serialNumber = "iflytek-test";
        Log.i(TAG, "sn : " + EngineConstants.serialNumber);
        // 初始化AIUI(识别+语义+合成）
        mAIUIAgent = AiuiEngine.getInstance(mAIUIListener);
        if (mAIUIAgent != null) {
            setText("AIUI初始化成功");
        } else {
            setText("AIUI初始化失败");
        }
        //对音频的处理为不降噪唤醒直接送去识别，只保留1声道音频,
        SystemRecorder.AUDIO_TYPE_ASR = true;
        //初始化录音
        if(recorder==null) {
            recorder = RecorderFactory.getRecorder();
        }
        if (recorder != null) {
            setText("录音机初始化成功");
        } else {
            setText("录音机初始化失败");
        }
    }


    private void startRecord() {
        if (recorder != null) {
            int ret = recorder.startRecord();
            if (0 == ret) {
                setText("开启录音成功！");
            } else if (111111 == ret) {
                setText("异常,AlsaRecorder is null ...");
            } else {
                setText("开启录音失败，请查看/dev/snd/下的设备节点是否有777权限！\nAndroid 8.0 以上需要暂时使用setenforce 0 命令关闭Selinux权限！");
                destroyRecord();
            }
        }
    }

    private void stopRecord() {
        if (EngineConstants.isRecording && recorder != null) {
            recorder.stopRecord();
            checkSysc.setText("开始保存");
            EngineConstants.isRecording = false;
            setText("停止录音");
        }
    }


    private void destroyRecord() {
        if (null != recorder) {
            recorder.stopRecord();
        } else {
            Log.d(TAG, "destroy is Done!");
        }
    }

    private void syncContacts() {
        // 从文件中读取联系人示例数据
        String dataStr = FileUtil.readFile(this, "data/data_contact.txt", "utf-8");
        setText("读取内容：" + dataStr);

        // 数据进行no_wrap Base64编码
        String dataStrBase64 = Base64.encodeToString(dataStr.getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP);

        JSONObject dataParamJson = new JSONObject();
        // 设置id_name为uid，即用户级个性化资源
        // 个性化资源使用可参考https://aiui-doc.xf-yun.com/project-1/doc-24/
        dataParamJson.put("id_name", "uid");
        // 设置res_name为联系人
        dataParamJson.put("res_name", "IFLYTEK.telephone_contact");

        JSONObject syncSchemaJson = new JSONObject();
        syncSchemaJson.put("param", dataParamJson);
        syncSchemaJson.put("data", dataStrBase64);

        // 给该次同步加上自定义tag，在返回结果中可通过tag将结果和调用对应起来
        JSONObject paramJson = new JSONObject();
        paramJson.put("tag", "sync-tag");

        //传数据给服务器，必须在连接服务器之后，否则失败
        AiuiEngine.DynamicEntity_sync(paramJson, syncSchemaJson);
    }


    /**
     * 根据scrollView 和子view去测量滑动的位置
     *
     * @param scrollView
     * @param view
     */
    private void scrollToBottom(final ScrollView scrollView, final View view) {

        handler.post(() -> {
            if (scrollView == null || view == null) {
                return;
            }
            // offset偏移量。是指当textview中内容超出 scrollview的高度，那么超出部分就是偏移量
            int offset = view.getMeasuredHeight()
                    - scrollView.getMeasuredHeight();
            if (offset < 0) {
                offset = 0;
            }
            //scrollview开始滚动
            scrollView.scrollTo(0, offset);
        });
    }

    private void setText(final String str) {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            mResText.append(str + " \n");
            scrollToBottom(mScrollView, mResText);
        } else {
            runOnUiThread(() -> {
                mResText.append(str + " \n");
                scrollToBottom(mScrollView, mResText);
            });
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (EngineConstants.isRecording) {
            stopRecord();
        }
        if (recorder != null) {
            recorder = null;
        }
        if (mAIUIListener != null) {
            mAIUIListener = null;
        }
        AiuiEngine.destroy();
    }
}